package com.tte.common.utils.office;

import com.deepoove.poi.NiceXWPFDocument;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.util.*;

public class WordByPoi {
    public static String tempFilePath = "D:\\temp\\模板.docx";
    public static String newFilePath = "D:\\temp\\\\模板1.docx";
    public static String newFilePath2 = "D:\\temp\\模板2.docx";

    public static void main(String[] args) throws Exception {

        MergeFileAndReplaceTitle(null,newFilePath2);

//
//        createTable(5);
//        changWord("","",new HashMap<>(),new ArrayList<>());
    }
    /**
     * MergeFileAndReplaceTitle(ArrayList<ArrayList<String>> fileList,String destFile)
     * @param fileList 文件名和标题列表：[D:\poitl中文\文档1.docx, 标题111111],[D:\poitl中文\文档1.docx, 标题22222]...]
     * @param destFile 输出文件名
     */
    public static void MergeFileAndReplaceTitle(ArrayList<ArrayList<String>> fileList,String destFile) {
        String template = tempFilePath;
        String blankFile = newFilePath;//用于创建空白word文件
        try {
            NiceXWPFDocument tempDocument = new NiceXWPFDocument(new FileInputStream(template));//样式模板文档
            NiceXWPFDocument newDoc = new NiceXWPFDocument(new FileInputStream(blankFile));
            ArrayList<String> allFileStyles = new ArrayList<String>();
            for(ArrayList<String> obj :fileList) {
                String filePath = obj.get(0);
                NiceXWPFDocument srcDocument = new NiceXWPFDocument(new FileInputStream(filePath));
                XWPFParagraph p1 = srcDocument.getParagraphArray(0);
                p1.removeRun(0);//删除第一段原内容
                p1.createRun().setText(obj.get(1));
                List<XWPFParagraph> srcPList = srcDocument.getParagraphs();
                for(int i = 0;i<srcPList.size();i++) {
                    allFileStyles.add(srcPList.get(i).getStyleID());
                }
                newDoc = newDoc.merge(srcDocument);
            }
            List<XWPFParagraph> newDocParagraphs = newDoc.getParagraphs();
            for(int i = 1;i<newDocParagraphs.size();i++) {//空白文档模板有1行
                newDocParagraphs.get(i).setStyle(allFileStyles.get(i-1));
            }
            newDoc.createStyles().setStyles(tempDocument.getStyle());
            FileOutputStream out = new FileOutputStream(destFile);
            newDoc.write(out);
            System.out.println(destFile + "文件输出成功");
            newDoc.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }



    // ***************************************************************************************************************


    /**
     * 根据模板生成新word文档
     * 判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
     *
     * @param templatePath 模板存放地址
     * @param newFilePath  新文档存放地址
     * @param dataMap      需要替换的信息集合
     * @param dataList     需要插入的表格信息集合
     * @return 成功返回true, 失败返回false
     */
    public static boolean changWord(String templatePath, String newFilePath,
                                    Map<String, String> dataMap, List<String[]> dataList) {

        dataMap = new HashMap<String, String>();
        dataMap.put("FieldColumnName", "主键");
        dataMap.put("FieldDataType", "INT");
        dataMap.put("FieldNullAble", "N");
        dataMap.put("FieldPrimary", "Y");
        dataMap.put("FieldAutoIncrement", "N");
        dataMap.put("FieldDefaultVal", "");
        dataMap.put("FieldComments", "主键ID");

        dataList = new ArrayList<String[]>();
        dataList.add(new String[]{"1","1AA","1BB","1CC","1DD","1EE","1FF"});
        dataList.add(new String[]{"2","2AA","2BB","2CC","2DD","2EE","2FF"});
        dataList.add(new String[]{"3","3AA","3BB","3CC","3DD","3EE","3FF"});
        dataList.add(new String[]{"4","4AA","4BB","4CC","4DD","4EE","4FF"});


        //模板转换默认成功
        boolean changeFlag = true;
        try {
            //获取docx解析对象
            XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(tempFilePath));
            //解析替换文本段落对象
            changeText(document, dataMap);
            //解析替换表格对象
            changeTable(document, dataMap, dataList);

            //生成新的word
            File file = new File(newFilePath2);
            FileOutputStream stream = new FileOutputStream(file);
            document.write(stream);
            stream.close();

        } catch (IOException e) {
            e.printStackTrace();
            changeFlag = false;
        }

        return changeFlag;

    }

    /**
     * 替换段落文本
     *
     * @param document docx解析对象
     * @param textMap  需要替换的信息集合
     */
    private static void changeText(XWPFDocument document, Map<String, String> textMap) {
        //获取段落集合
        List<XWPFParagraph> paragraphs = document.getParagraphs();

        for (XWPFParagraph paragraph : paragraphs) {
            //判断此段落时候需要进行替换
            String text = paragraph.getText();
            if (checkText(text)) {
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //替换模板原来位置
                    run.setText(changeValue(run.toString(), textMap), 0);
                }
            }
        }

    }

    /**
     * 替换表格对象方法
     *
     * @param document  docx解析对象
     * @param textMap   需要替换的信息集合
     * @param tableList 需要插入的表格信息集合
     */
    private static void changeTable(XWPFDocument document, Map<String, String> textMap,
                                    List<String[]> tableList) {
        //获取表格对象集合
        List<XWPFTable> tables = document.getTables();
        for (XWPFTable table : tables) {
            //只处理行数大于等于2的表格，且不循环表头
            if (table.getRows().size() > 1) {
                //判断表格是需要替换还是需要插入，判断逻辑有$为替换，表格无$为插入
                if (checkText(table.getText())) {
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(rows, textMap);
                } else {
                    insertTable(table, tableList);
                }
            }
        }
    }

    /**
     * 遍历表格
     *
     * @param rows    表格行对象
     * @param textMap 需要替换的信息集合
     */
    private static void eachTable(List<XWPFTableRow> rows, Map<String, String> textMap) {
        for (XWPFTableRow row : rows) {
            List<XWPFTableCell> cells = row.getTableCells();
            for (XWPFTableCell cell : cells) {
                //判断单元格是否需要替换
                if (checkText(cell.getText())) {
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    for (XWPFParagraph paragraph : paragraphs) {
                        List<XWPFRun> runs = paragraph.getRuns();
                        for (XWPFRun run : runs) {
                            run.setText(changeValue(run.toString(), textMap), 0);
                        }
                    }
                }
            }
        }
    }

    /**
     * 为表格插入数据，行数不够添加新行
     *
     * @param table     需要插入数据的表格
     * @param tableList 插入数据集合
     */
    private static void insertTable(XWPFTable table, List<String[]> tableList) {
        //创建行,根据tableList决定需要插入的几行，不处理表头
        for (int i = 1; i < tableList.size(); i++) {
            XWPFTableRow row = table.createRow();//table.addRow(table.getRow(1));
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1; i < rows.size(); i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                cell.setText("测试");//cell.setText(tableList.get(i-1)[0]);
            }
        }
        table.getRow(1).getTableCells().get(1).setText("设置");

    }


    /**
     * 判断文本中时候包含$
     *
     * @param text 文本
     * @return 包含返回true, 不包含返回false
     */
    private static boolean checkText(String text) {
        boolean check = false;
        if (text.indexOf("$") != -1) {
            check = true;
        }
        return check;

    }

    /**
     * 匹配传入信息集合与模板
     *
     * @param value   模板需要替换的区域
     * @param textMap 传入信息集合
     * @return 模板需要替换区域信息集合对应值
     */
    private static String changeValue(String value, Map<String, String> textMap) {
        Set<Map.Entry<String, String>> textSets = textMap.entrySet();
        for (Map.Entry<String, String> textSet : textSets) {
            //匹配模板与替换值 格式${key}
            String key = "${" + textSet.getKey() + "}";
            if (value.indexOf(key) != -1) {
                value = textSet.getValue();
            }
        }
        //模板未匹配到区域替换为空
        if (checkText(value)) {
            value = "";
        }
        return value;
    }


    /**
     * 产生多份文件
     * @param copies 文件分数
     */
    public static void createFileCopy(int copies) {
        String sourceFile = tempFilePath; // Word源文件
        String outputFolder = "C:\\Users\\TTE\\Desktop"; // 输出文件夹
        try {
            InputStream in = new FileInputStream(sourceFile);
            XWPFDocument doc = new XWPFDocument(in);

            for (int i = 0; i < copies; i++) {
                String outputFile = outputFolder + "/copy" + (i + 1) + ".docx";
                OutputStream out = new FileOutputStream(outputFile);
                doc.write(out); // 将文档写入输出流（即创建副本）
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 复制表格暂时有问题，会把模板修改
     * @param copies 文件分数
     */
    public static void createTable(int copies) {
        try {
            //使用 XWPFDocument 类加载文
            XWPFDocument doc = new XWPFDocument(POIXMLDocument.openPackage(tempFilePath));
            //获取文档中的所有表格，使用 XWPFTable 类获取表格对象
            List<XWPFTable> tables = doc.getTables();
            //遍历要复制的表格，使用 XWPFTable 类的 clone 方法复制表格
            XWPFTable table = tables.get(0);
            for (int c = 0; c < copies; c++) {
                XWPFTable newTable = doc.insertNewTbl(table.getCTTbl().newCursor());
//                newTable.getCTTbl().setTblPr(table.getCTTbl().getTblPr());
//                newTable.getCTTbl().setTblGrid(table.getCTTbl().getTblGrid());
                for (int i = 0; i < table.getRows().size(); i++) {
                    XWPFTableRow row = newTable.createRow();
                    for (int j = 0; j < table.getRow(i).getTableCells().size(); j++) {
                        XWPFTableCell cell = row.getCell(j);
                        if (cell == null) {
                            cell = row.createCell();
                        }
                        cell.getCTTc().setTcPr(table.getRow(i).getCell(j).getCTTc().getTcPr());
                        cell.setText(table.getRow(i).getCell(j).getText());
                    }
                }
                // 创建一个段落
                XWPFParagraph p = doc.createParagraph();
                // 在该段落中创建一个运行对象
                XWPFRun r = p.createRun();
//                // 添加文本内容
//                r.setText("这是第一行文本。");
                // 插入换行
                r.addBreak();
//                // 继续添加文本内容
//                r.setText("这是第二行文本。");
            }
            doc.write(new FileOutputStream(newFilePath2));
            doc.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void tese1(int copies) {
        //使用 XWPFDocument 类加载文
        XWPFDocument doc = null;
        try {
            doc = new XWPFDocument(POIXMLDocument.openPackage(tempFilePath));
            //获取文档中的所有表格，使用 XWPFTable 类获取表格对象
            List<XWPFTable> tables = doc.getTables();
            XWPFTable table = tables.get(0);
            for (int i = 0; i < copies; i++) {
                XWPFTable table1 = doc.createTable();
                table1 = table;
                doc.insertTable(i,table1);
            }
            doc.write(new FileOutputStream(newFilePath2));
            doc.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


}
